package at.ac.univie.zsu.aguataplan.ui.template;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;

import org.jdesktop.swingx.JXList;

import at.ac.univie.zsu.aguataplan.property.GeneralProperties;
import at.ac.univie.zsu.aguataplan.property.I18nProperties;
import at.ac.univie.zsu.aguataplan.ui.UIConstants;

/**
 * TODO: there is a refresh of all components no matter if operation works -
 * maybe not necessary
 * 
 * @author gerry
 * 
 */
public class ListEntryPanel extends JPanel implements UIConstants {

	private static final long serialVersionUID = 1L;

	// general members
	private JDialog dialogParent;
	private GeneralProperties generalProperties;
	private I18nProperties i18nProp;
	private IDialogListEntry iDialogListEntry;

	// buttons
	private JButton addBtn;
	private JButton deleteBtn;
	private JButton saveBtn;

	// list
	private JScrollPane listScroll;
	private JXList list;
	// private JScrollPane listScroll;
	// private JList list;
	private DefaultListModel listModel;

	// text elements
	private List<JLabel> labels;
	private List<JTextField> texts;

	// combo box elements
	private List<JLabel> comboLabels;
	private List<JComboBox> combos;

	// date panel elements
	private List<JLabel> dateLabels;
	private List<DatePanel> datePanels;

	// button elements
	private List<JButton> buttons;

	// relationship
	private List<ListEntryPanel> parents;
	private List<ListEntryPanel> children;

	private int tmpI;

	// ----------------------------------------------------
	// CONSTRUCTOR
	// ----------------------------------------------------

	public ListEntryPanel(JDialog dialogParent, GeneralProperties generalProperties, IDialogListEntry iDialog) {

		this.dialogParent = dialogParent;
		this.generalProperties = generalProperties;
		this.i18nProp = generalProperties.getI18nProperties();
		this.iDialogListEntry = iDialog;

		parents = new ArrayList<ListEntryPanel>();
		children = new ArrayList<ListEntryPanel>();

		this.setLayout(null);

		tmpI = 0;

	}

	// ----------------------------------------------------
	// METHODS
	// ----------------------------------------------------

	public void addChild(ListEntryPanel entryPanel) {
		children.add(entryPanel);
	}

	public void addParent(ListEntryPanel entryPanel) {
		parents.add(entryPanel);
	}

	public void init(String borderName, int sizeX, int sizeY, List<String> ls, List<String> cLs, List<String> dLs,
			List<String> bLs, List<ActionListener> aLs) {

		this.setBorder(javax.swing.BorderFactory.createTitledBorder(borderName));

		listScroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		list = new JXList();
		// list = new JList();
		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.setModel(getListModel());
		listScroll.setSize(LIST_SIZE_X, sizeY - LIST_SIZE_Y_FREE_SPACE);
		listScroll.setLocation(LIST_LOCATION_X, LIST_LOCATION_Y);

		listScroll.getViewport().add(list);
		this.add(listScroll);

		addBtn = new JButton(i18nProp.getString(ADD_BUTTON));
		addBtn.setSize(BUTTON_SIZE_X, BUTTON_SIZE_Y);
		deleteBtn = new JButton(i18nProp.getString(DELETE_BUTTON));
		deleteBtn.setSize(BUTTON_SIZE_X, BUTTON_SIZE_Y);
		saveBtn = new JButton(i18nProp.getString(SAVE_BUTTON));
		saveBtn.setSize(BUTTON_SIZE_X, BUTTON_SIZE_Y);

		addBtn.setLocation(BUTTON_ADD_POSITION_X, sizeY - BUTTON_POSITION_FREE_SPACE);
		deleteBtn.setLocation(BUTTON_DELETE_POSITION_X, sizeY - BUTTON_POSITION_FREE_SPACE);
		saveBtn.setLocation(BUTTON_SAVE_POSITION_X, sizeY - BUTTON_POSITION_FREE_SPACE);

		this.add(addBtn);
		this.add(deleteBtn);
		this.add(saveBtn);

		initText(ls);
		initCombo(cLs);
		initDate(dLs);
		initButtons(bLs, aLs);
		initListModel();

		// Listener
		// -------------------------------
		// click on free area
		addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				cleanText();

				// disable children
				disableChildren();

			}
		});

		// click on list to select entry
		list.addMouseListener(new java.awt.event.MouseAdapter() {
			public void mouseClicked(java.awt.event.MouseEvent evt) {
				Object obj = list.getSelectedValue();
				if (obj == null) {
					return;
				}

				List<String> list = iDialogListEntry.select(obj);
				if (list != null) {
					for (int i = 0; i < list.size(); i++) {
						texts.get(i).setText(list.get(i));
					}
				}

				List<Integer> listCombo = iDialogListEntry.selectCombo(obj);
				if (listCombo != null) {
					for (int i = 0; i < listCombo.size(); i++) {
						combos.get(i).setSelectedIndex(listCombo.get(i));
					}
				}

				List<Date> listDate = iDialogListEntry.selectDate(obj);
				if (listDate != null) {
					for (int i = 0; i < listDate.size(); i++) {
						datePanels.get(i).setDate(listDate.get(i));
					}
				}

				// init children
				for (ListEntryPanel c : children) {
					c.initListModel();
				}

			}
		});

		addBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				iDialogListEntry.add(getList(), getCombos(), getDates());

				initListModel();

				// adapt parents
				adaptParents();

				cleanText();
			}
		});
		deleteBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				Object obj = list.getSelectedValue();
				if (obj == null) {
					return;
				}

				iDialogListEntry.delete(obj);

				initListModel();

				// adapt parents
				adaptParents();

				cleanText();
			}
		});
		saveBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Object obj = list.getSelectedValue();
				if (obj == null) {
					return;
				}

				iDialogListEntry.merge(obj, getList(), getCombos(), getDates());

				initListModel();

				// adapt parents
				adaptParents();

				cleanText();

			}
		});

		this.setSize(sizeX, sizeY);
		setVisible(true);
	}

	public void finishInit() {
		disableChildren();
	}

	// ----------------------------------------------------
	// METHODS PRIVATE
	// ----------------------------------------------------

	private ListModel getListModel() {

		if (listModel == null) {
			listModel = new DefaultListModel();

		}
		return listModel;
	}

	private void initText(List<String> ls) {
		labels = new ArrayList<JLabel>();
		texts = new ArrayList<JTextField>();

		for (int i = 0; i < ls.size(); i++) {
			JLabel l = new JLabel(ls.get(i));
			l.setSize(LABEL_SIZE_X, LABEL_SIZE_Y);
			l.setLocation(180, 20 + tmpI * LINE_INCREMENT);
			labels.add(l);

			JTextField t = new JTextField();
			t.setSize(TEXT_SIZE_X, TEXT_SIZE_Y);
			t.setLocation(280, 20 + tmpI * LINE_INCREMENT);
			texts.add(t);

			this.add(l);
			this.add(t);
			tmpI++;
		}
	}

	private void initCombo(List<String> ls) {
		comboLabels = new ArrayList<JLabel>();
		combos = new ArrayList<JComboBox>();

		for (int i = 0; i < ls.size(); i++) {
			JLabel l = new JLabel(ls.get(i));
			l.setSize(LABEL_SIZE_X, LABEL_SIZE_Y);
			l.setLocation(180, 20 + tmpI * LINE_INCREMENT);
			comboLabels.add(l);

			JComboBox c = new JComboBox();
			c.setSize(COMBO_SIZE_X, COMBO_SIZE_Y);
			c.setLocation(280, 20 + tmpI * LINE_INCREMENT);
			combos.add(c);

			this.add(l);
			this.add(c);
			tmpI++;

		}

	}

	private void initDate(List<String> ls) {
		dateLabels = new ArrayList<JLabel>();
		datePanels = new ArrayList<DatePanel>();

		for (int i = 0; i < ls.size(); i++) {
			JLabel l = new JLabel(ls.get(i));
			l.setSize(LABEL_SIZE_X, LABEL_SIZE_Y);
			l.setLocation(180, 20 + tmpI * LINE_INCREMENT);
			dateLabels.add(l);

			DatePanel datePanel = new DatePanel(new Date());
			datePanel.setSize(DatePanel.SIZE_X, DatePanel.SIZE_Y);
			datePanel.setLocation(230, 20 + tmpI * LINE_INCREMENT);
			datePanels.add(datePanel);

			this.add(l);
			this.add(datePanel);
			tmpI++;

		}
	}

	private void initButtons(List<String> ls, List<ActionListener> aLs) {
		buttons = new ArrayList<JButton>();

		for (int i = 0; i < ls.size(); i++) {
			JButton button = new JButton(ls.get(i));
			button.setLocation(230, 20 + tmpI * LINE_INCREMENT);
			button.setSize(BUTTON_SIZE_X, BUTTON_SIZE_Y);
			button.addActionListener(aLs.get(i));
			buttons.add(button);

			this.add(button);
			tmpI++;

		}
	}

	private void initListModel() {
		disableButton();
		List<?> tmpListText = null;
		if ((tmpListText = iDialogListEntry.initText()) != null) {
			listModel.clear();
			for (Object o : tmpListText) {
				listModel.addElement(o);
			}
		}

		int i = 0;
		List<List<?>> tmpListCombo;
		if ((tmpListCombo = iDialogListEntry.initCombo()) != null) {
			for (Object o1 : tmpListCombo) {
				combos.get(i).removeAllItems();
				List<?> l = (List<?>) o1;
				for (Object o2 : l) {
					combos.get(i).addItem(o2);
				}
				combos.get(i).setSelectedIndex(-1);
				i++;
			}
		}
		int j = 0;
		List<Date> tmpListDate;
		if ((tmpListDate = iDialogListEntry.initDate()) != null) {
			for (Date d : tmpListDate) {
				datePanels.get(j).setDate(d);
				j++;
			}
		}

		enableButton();
	}

	private void adaptParents() {
		for (ListEntryPanel parent : parents) {
			int index = parent.list.getSelectedIndex();
			parent.initListModel();
			parent.list.setSelectedIndex(index);
		}
	}

	private void disableChildren() {
		for (ListEntryPanel c : children) {
			c.disableButton();
		}
	}

	private void cleanText() {
		// clean text fields
		for (JTextField tf : texts) {
			tf.setText(EMPTY);
		}

		for (JComboBox cb : combos) {
			// cb.removeAllItems();
			cb.setSelectedIndex(-1);
		}

		for (DatePanel d : datePanels) {
			d.cleanPanel();
		}

		// clean list selection
		list.clearSelection();

	}

	private void disableButton() {
		// disable buttons
		addBtn.setEnabled(false);
		deleteBtn.setEnabled(false);
		saveBtn.setEnabled(false);

		// disable list
		listModel.clear();
		list.setEnabled(false);

		// disable text fields
		for (JTextField tf : texts) {
			tf.setText(EMPTY);
			tf.setEnabled(false);
		}

		for (JComboBox c : combos) {
			c.setEnabled(false);
		}

		for (JButton b : buttons) {
			b.setEnabled(false);
		}

		for (DatePanel d : datePanels) {
			d.cleanPanel();
		}

	}

	private void enableButton() {
		// enable buttons
		addBtn.setEnabled(true);
		deleteBtn.setEnabled(true);
		saveBtn.setEnabled(true);

		// enable list
		list.setEnabled(true);

		// enable text fields
		for (JTextField tf : texts) {
			tf.setText(EMPTY);
			tf.setEnabled(true);
		}

		for (JComboBox c : combos) {
			c.setEnabled(true);
		}

		for (JButton b : buttons) {
			b.setEnabled(true);
		}

	}

	private List<Date> getDates() {
		List<Date> dates = new ArrayList<Date>();

		for (DatePanel datePanel : datePanels) {
			dates.add(datePanel.getDate());
		}

		return dates;
	}

	private List<String> getList() {
		List<String> lists = new ArrayList<String>();
		for (JTextField tf : texts) {
			lists.add(tf.getText());
		}
		return lists;
	}

	private List<Object> getCombos() {
		List<Object> listCombo = new ArrayList<Object>();
		for (JComboBox c : combos) {
			listCombo.add(c.getSelectedItem());
		}

		return listCombo;
	}

	public Object getSelectedValueEntry() {
		return list.getSelectedValue();
	}

}
